﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using ScrumTable.Config.ConfigManagement;
using ScrumTable.BL.DM.DataManagement;
using ScrumTable.UI.ViewModel.Data;
 
#endregion

namespace ScrumTable.UI.ViewModel
{
    /// <summary>
    /// User story for the View model
    /// </summary>
    public class UserStoryViewModel : ViewModelItemBase<UserStory>
    {

        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------
        /// <summary>
        /// The user story from the BL.
        /// </summary>
 
        private double _totalWorkCompleted;
        private double _totalWorkRemaining;
        private bool _isExpaned = true;
 
         
        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------
  

        /// <summary>
        /// Func for changing the state
        /// </summary>
        public static readonly Func<object, ScrumState, CanDropResult> CanChangeState = CanChangeStateResult<UserStoryViewModel>;
      
        
        /// <summary>
        /// Gets a list of all tasks associated to the current user story.
        /// </summary>
        public DomainCollection<Task> Tasks
        {
            get { return IsDisposed ? null : Original.Tasks; }
        }

        /// <summary>
        /// Gets a list of all bugs.
        /// </summary>
        public DomainCollection<Bug> Bugs
        {
            get { return IsDisposed ? null : Original.Bugs; }
        }

        private ObservableDomainCollection<TaskViewModel, Task> _tasksViewModel;
        /// <summary>
        /// Gets the task list as a view model list.
        /// </summary>
        /// <value>The tasks as view model.</value>
        public ObservableDomainCollection<TaskViewModel, Task> TasksAsViewModel
        {
            get
            {
                if (_tasksViewModel == null && Tasks !=null) 
                {
                    _tasksViewModel = new ObservableDomainCollection<TaskViewModel, Task>();
                    _tasksViewModel.Fill(Tasks, task => new TaskViewModel(task));
                }
                return _tasksViewModel;
            }
        }


        /// <summary>
        /// Sorting property
        /// </summary>
        public override double? Sorting
        {
            get { return Ranking; }
        }


        /// <summary>
        /// Specifies the story points assigned to the current user story.
        /// </summary>
        public double? StoryPoints
        {
            get { return IsDisposed ? null : Original.StoryPoints; }
            set
            {
                if (Original != null)
                {
                    Original.StoryPoints = value;
                    SendPropertyChanged("StoryPoints");
                }
                Save();
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this userstory is shown in expand mode (like more information...).
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this story is expaned; otherwise, <c>false</c>.
        /// </value>
        public bool IsExpaned
        {
            get { return _isExpaned; }
            set
            {
                _isExpaned = value;
                SendPropertyChanged("IsExpaned");
            }
        }
   
        /// <summary>
        /// Gets the total work completed. Over all Tasks.
        /// </summary>
        /// <value>The total work completed.</value>
        public double TotalWorkCompleted
        {
            get { return _totalWorkCompleted;  }
        }
        
        /// <summary>
        /// Gets the total work remaining. Over all Tasks.
        /// </summary>
        /// <value>The total work remaining.</value>
        public double TotalWorkRemaining
        {
            get { return _totalWorkRemaining; }
        }

        #endregion

        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------
        /// <summary>
        /// Initializes a new instance of the <see cref="UserStoryViewModel"/> class.
        /// </summary>
        /// <param name="userStory">The user story.</param>
        public UserStoryViewModel(UserStory userStory):base(userStory)
        { 
            Original.Context.ElementChanged += OnDataContextElementChanged;
            Original.Tasks.CollectionChanged += OnTaskCollectionChanged;
            UpdateTotalWork();
        }

       
    
        /// <summary>
        /// Releases managed (c# or .net) resources.
        /// </summary>
        protected override void ReleaseManagedResources()
        {
            if (Original != null)
            {
                Original.Context.ElementChanged -= OnDataContextElementChanged;
            }
            if (_tasksViewModel != null)
            {
                foreach (var taskViewModel in TasksAsViewModel)
                {
                    taskViewModel.Dispose();
                }
                _tasksViewModel.Dispose();
                _tasksViewModel = null;
            }
            base.ReleaseManagedResources();
        }

        #endregion

        #region Overrides

        /// <summary>
        /// Determines whether the specified <see cref="System.Object"/> is equal to this instance.
        /// </summary>
        /// <param name="obj">The <see cref="System.Object"/> to compare with this instance.</param>
        /// <returns>
        /// 	<c>true</c> if the specified <see cref="System.Object"/> is equal to this instance; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="T:System.NullReferenceException">
        /// The <paramref name="obj"/> parameter is null.
        /// </exception>
        public override bool Equals(object obj)
        {
            if (obj is UserStoryViewModel) return Equals(obj as UserStoryViewModel);
            if (obj is UserStory) return Original.Equals(obj);

            return false;
        }

        /// <summary>
        /// Equalses the specified other.
        /// </summary>
        /// <param name="other">The other.</param>
        /// <returns></returns>
        public bool Equals(UserStoryViewModel other)
        {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.Id == Id; 
        }

        /// <summary>
        /// Returns a hash code for this instance.
        /// </summary>
        /// <returns>
        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
        /// </returns>
        public override int GetHashCode()
        {
            return (Original != null ? Original.GetHashCode() : 0);
        }

        #endregion

        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------
 

        /// <summary>
        /// Updates the total work.
        /// </summary>
        public void UpdateTotalWork()
        {
            _totalWorkCompleted = 0;
            _totalWorkRemaining = 0;
            foreach (var task in Tasks)
            {
                if(task.CompletedWork.HasValue)
                    _totalWorkCompleted += task.CompletedWork.Value;
                if (task.RemainingWork.HasValue)
                    _totalWorkRemaining += task.RemainingWork.Value;
            }
            SendPropertyChanged("TotalWorkCompleted");
            SendPropertyChanged("TotalWorkRemaining");
        }


        /// <summary>
        /// Gets the StackRank Sorter
        /// </summary>
        /// <param name="isDec">if true gets the desc sorter</param>
        /// <returns>Stack Rank Sorter</returns>
        public static Func<UserStoryViewModel, UserStoryViewModel, int> GetStackRankSorter(bool isDec)
        {
            if (isDec)
            {
                return (x, y) =>
                {
                    double iX = 0;
                    double iY = 0;
                    if (x.Ranking.HasValue)
                        iX = x.Ranking.Value;
                    if (y.Ranking.HasValue)
                        iY = y.Ranking.Value;

                    return iY.CompareTo(iX);
                };
            }

            return (x, y) =>
            {
                double iX = 0;
                double iY = 0;
                if (x.Ranking.HasValue)
                    iX = x.Ranking.Value;
                if (y.Ranking.HasValue)
                    iY = y.Ranking.Value;
                return iX.CompareTo(iY);
            };

        }
        #endregion

        #region Events
        //--------------------------------------------------------------------
        // Events
        //--------------------------------------------------------------------

        
        /// <summary>
        /// Called when [data context element changed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        public void OnDataContextElementChanged(object sender, PropertyChangedEventArgs e)
        {
            var args = e as DomainChangedEventArgs;
            if (args == null) return;
            if (!args.ContainsType<Task>()) return;
            
            if (args.ContainsElementId(Id, true) && args.ContainsPropertyNames("CompletedWork" , "RemainingWork"))
            {
                UpdateTotalWork();
            }
        }

        private void OnTaskCollectionChanged(object sender, DomainCollectionChangedEventArgs e)
        {
            UpdateTotalWork();
        }
        
        #endregion
    }
}